package com.pansoft.openplanet.account.util;

import com.efounder.util.FileDeleteUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pansoft.hd.HDAccountManager;
import com.pansoft.hd.HDWalletUtil;
import com.pansoft.hd.model.BaseHDWallet;
import com.pansoft.openplanet.account.model.EthBean;
import com.pansoft.openplanet.constant.IPAssetsConstant;
import com.pansoft.openplanet.util.EthHDWalletUtils;

import org.bitcoinj.wallet.DeterministicSeed;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Wallet;
import org.web3j.crypto.WalletFile;

import java.io.File;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;

/**
 * eth账户生成
 *
 * @author YQS 2018/06/08
 */
public class EthAccountGenerator {
    private static final String TAG = "EthAccountGenerator";


    /**
     * todo 异步方法创建账户
     *
     * @param keyStoreDirPath keystore文件存放目录
     * @return
     * @throws Exception
     */
    public static Disposable createEthAccountAsync(final String keyStoreDirPath, final GeneratorListener generatorListener) {
        if (keyStoreDirPath == null) {
            if (generatorListener != null) {
                generatorListener.generatorFail();
            }
            return null;
        }
        //如果目录不存在，创建目录
        File file = new File(keyStoreDirPath);
        if (!file.exists() || !file.isDirectory()) {
            file.mkdirs();
        }

        Disposable disposable = Observable.create(new ObservableOnSubscribe<EthBean>() {
            @Override
            public void subscribe(ObservableEmitter<EthBean> emitter) throws Exception {
                EthBean ethBean = createEthAccountSync(keyStoreDirPath);
                emitter.onNext(ethBean);
                emitter.onComplete();
            }
        })        // 在io线程生成walletfile的进行操作
                .subscribeOn(Schedulers.io())
                // 在主线程处理walletfile保存
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<EthBean>() {
                    @Override
                    public void accept(@NonNull EthBean ethBean) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorSuccess(ethBean);
                        }

                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorFail();
                        }
                    }
                });
        return disposable;
    }

    /**
     * todo 同步方法创建 账户
     *
     * @param keyStoreDirPath keystore 文件存放目录
     * @return
     * @throws Exception
     */
    public static EthBean createEthAccountSync(String keyStoreDirPath) throws Exception {

//        if (EnvSupportManager.isSupportHDWallet()) {
//            //todo HD钱包我们使用这种方式创建
//            HDAccountManager hdAccountManager = new HDAccountManager();
//            List<String> mnemonicList = hdAccountManager.createRandomMnemonic();
//            IHDWallet hdWallet = hdAccountManager.createETHWallet(mnemonicList, "", keyStoreDirPath);
//
//            EthHdWallet ethHDWallet = (EthHdWallet) hdWallet;
//            EthBean ethBean = new EthBean.Builder()
//                    .ethAddress(ethHDWallet.getAddress())
//                    .ecKeyPair(ethHDWallet.getEcKeyPair())
//                    .keyStoreFilePath(ethHDWallet.getFilePath())
//                    .mnemonicList(mnemonicList)
//                    .mnemonic(HDWalletUtil.mnemonic2String(mnemonicList))
//                    .build();
//            return ethBean;
//        }


        DeterministicSeed ds = EthHDWalletUtils.createRandomDeterministicSeed("");
        List<String> mnemonicList = ds.getMnemonicCode();

        String mnemonic = HDWalletUtil.mnemonic2String(mnemonicList);
        //生成密钥
        ECKeyPair ecKeyPair = EthHDWalletUtils.createECKeyPairFromSeed(ds);
        //生成walletfile
        WalletFile walletFile = Wallet.createLight("", ecKeyPair);
        //生成keystore文件名称
        SimpleDateFormat dateFormat = new SimpleDateFormat("'UTC--'yyyy-MM-dd'T'HH-mm-ss.SSS'--'");
        String fileName = dateFormat.format(new Date()) + walletFile.getAddress() + ".json";
        //钱包地址
        String ethAddress = "0x" + walletFile.getAddress();
        //keystore文件
        File keyStoreFile = new File(keyStoreDirPath, fileName);
        //保存keystore 写入文件
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.writeValue(keyStoreFile, walletFile);

        EthBean ethBean = new EthBean.Builder()
                .ethAddress(ethAddress)
                .ecKeyPair(ecKeyPair)
                .keyStoreFilePath(keyStoreFile.getAbsolutePath())
                .mnemonicList(mnemonicList)
                .walletFile(walletFile)
                .mnemonic(mnemonic)
                .build();

        return ethBean;
    }

    /**
     * todo 使用助记词恢复钱包
     *
     * @param keyStoredirPath   keystore 路径
     * @param mnemoric          助记词（" "分割）
     * @param generatorListener
     * @return
     */
    public static Disposable recoverAccountByMnemoric(final String keyStoredirPath, final String mnemoric, final IPAssetsConstant.ChainEnum chainEnum,
                                                      final GeneratorListener generatorListener) {
        //如果目录不存在，创建目录
        File file = new File(keyStoredirPath);
        if (!file.exists() || !file.isDirectory()) {
            file.mkdirs();
        }
        Disposable disposable = Observable.create(new ObservableOnSubscribe<EthBean>() {
            @Override
            public void subscribe(ObservableEmitter<EthBean> emitter) throws Exception {
                //助记词恢复
//                EthBean ethBean = EthHDWalletUtils.generateWalletFile(mnemoric, "");
                //todo yqs 使用新方式生成
                HDAccountManager hdAccountManager = new HDAccountManager();
                BaseHDWallet ihdWallet = hdAccountManager.createWallet(HDWalletUtil.mnemonicString2List(mnemoric), "", keyStoredirPath, chainEnum);
                EthBean ethBean = hdAccountManager.convertHDWallet2ETHBean(ihdWallet);
                emitter.onNext(ethBean);
                emitter.onComplete();
            }

        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<EthBean>() {
                    @Override
                    public void accept(EthBean ethBean) throws Exception {

                        generatorListener.generatorSuccess(ethBean);


//                        SimpleDateFormat dateFormat = new SimpleDateFormat("'UTC--'yyyy-MM-dd'T'HH-mm-ss.SSS'--'");
//                        String fileName = dateFormat.format(new Date()) + ethBean.getWalletFile().getAddress() + ".json";
//                        File destination = new File(keyStoredirPath, fileName);
//                        ObjectMapper objectMapper = new ObjectMapper();
//                        //写入文件
//                        objectMapper.writeValue(destination, ethBean.getWalletFile());
//                        File realFile = new File(keyStoredirPath + File.separator + fileName);
//                        ethBean.setKeyStoreFilePath(realFile.getAbsolutePath());
//                        if (!realFile.exists()) {
//                            FileDeleteUtil.delete(realFile);
//                            if (generatorListener != null) {
//                                generatorListener.generatorFail();
//                            }
//                            return;
//                        } else {
//                            generatorListener.generatorSuccess(ethBean);
//                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorFail();
                        }
                    }
                });
        return disposable;
    }

    /**
     * todo 使用私钥恢复钱包
     *
     * @param keyStoredirPath   keystore 路径
     * @param key               私钥
     * @param generatorListener
     * @return
     */
    public static Disposable recoverAccountByPrivateKey(final String keyStoredirPath, String key,
                                                        final GeneratorListener generatorListener) {
        BigInteger privateKey = null;
        try {
            if (key.length() > 2) {
                if ("0x".equals(key.substring(0, 2).toLowerCase())) {
                    //去掉0X
                    key = key.substring(2, key.length());
                    // key = String16Utils.str2HexStr(key);
                    privateKey = new BigInteger(key, 16);
                } else {
                    privateKey = new BigInteger(key, 16);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (generatorListener != null) {
                generatorListener.generatorFail();
            }
        }

        final BigInteger finalPrivateKey = privateKey;
        Disposable disposable = Observable.create(new ObservableOnSubscribe<EthBean>() {
            @Override
            public void subscribe(ObservableEmitter<EthBean> emitter) throws Exception {
                ECKeyPair ecKeyPair = ECKeyPair.create(finalPrivateKey);
                WalletFile walletFile = Wallet.createLight("", ecKeyPair);

                EthBean ethBean = new EthBean.Builder()
                        .walletFile(walletFile)
                        .ecKeyPair(ecKeyPair)
                        .ethAddress("0x" + walletFile.getAddress())
                        .build();
                emitter.onNext(ethBean);
                emitter.onComplete();

            }

        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<EthBean>() {
                    @Override
                    public void accept(EthBean ethBean) throws Exception {
                        SimpleDateFormat dateFormat = new SimpleDateFormat("'UTC--'yyyy-MM-dd'T'HH-mm-ss.SSS'--'");
                        String fileName = dateFormat.format(new Date()) + ethBean.getWalletFile().getAddress() + ".json";
                        File destination = new File(keyStoredirPath, fileName);
                        ObjectMapper objectMapper = new ObjectMapper();
                        //写入文件
                        objectMapper.writeValue(destination, ethBean.getWalletFile());
                        File realFile = new File(keyStoredirPath + File.separator + fileName);
                        ethBean.setKeyStoreFilePath(realFile.getAbsolutePath());
                        if (!realFile.exists()) {
                            FileDeleteUtil.delete(realFile);
                            if (generatorListener != null) {
                                generatorListener.generatorFail();
                            }
                            return;
                        } else {
                            generatorListener.generatorSuccess(ethBean);
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorFail();
                        }
                    }
                });
        return disposable;

    }

    /**
     * 钱包创建恢复的回调
     */
    public interface GeneratorListener {
        //成功
        void generatorSuccess(EthBean ethBean);

        //失败
        void generatorFail();
    }
}
